﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ReporterEngine.Methods
{
    public class Condition : BaseMethod
    {
        public override bool IsUseable(LexPath.PathToken token)
        {
            return token.Kind == LexPath.TokenKind.Condition;// && !string.IsNullOrEmpty(token.PathExp);
        }

        public override sQuery Execute(LexPath.PathToken token, sQuery query)
        {
            var result = query.New();

            var startToken = token.SubToken;



            //get result and goto next condition
           


            foreach (var element in query.Elements)
            {
                var conditionToken = startToken;
                var totalConditionResult = false;

                while (conditionToken != null)
                {
                    if (conditionToken.Operator == LexPath.TokenOperator.Undefined)
                    {
                        result.ErrorMessage.AppendLine("Undefined operator for :" + token.StartEndString);
                        return result;
                    }
                    if(conditionToken.Left == null)
                    {
                        result.ErrorMessage.AppendLine("Missing left value for :" + token.StartEndString);
                        return result;
                    }
                    if (conditionToken.Right == null)
                    {
                        result.ErrorMessage.AppendLine("Missing right value for :" + token.StartEndString);
                        return result;
                    }
                    
                    var conditionResult = false;

                    var tempQuery = query.New();
                    tempQuery.Elements.Add(element);

                    var leftValue = ""; // Interpreter.Execute(conditionToken.Left, query);
                    var rightValue = ""; // Interpreter.Execute(conditionToken.Right, query);

                    sQuery leftQuery = null;
                    sQuery rightQuery = null;

                    if (conditionToken.Left.Kind == LexPath.TokenKind.String)
                    {
                        leftValue = sQuery.RemoveOnlyStringQuotations(conditionToken.Left.PathExp);
                    }
                    else if (conditionToken.Left.Kind == LexPath.TokenKind.Parameter)
                    {
                        var paramName = conditionToken.Left.PathExp;
                        leftValue = query._model.GetParameterValue(paramName);
                    }
                    else
                    {
                        leftQuery = Interpreter.Execute(conditionToken.Left, tempQuery);
                        leftValue = leftQuery.Value;
                    }

                    if (conditionToken.Right.Kind == LexPath.TokenKind.String)
                    {
                        rightValue = sQuery.RemoveOnlyStringQuotations(conditionToken.Right.PathExp);
                    }
                    else if (conditionToken.Right.Kind == LexPath.TokenKind.Parameter)
                    {
                        var paramName = conditionToken.Right.PathExp;
                        rightValue = query._model.GetParameterValue(paramName);
                    }
                    else
                    {
                        rightQuery = Interpreter.Execute(conditionToken.Right, tempQuery);
                        rightValue = rightQuery.Value;
                    }

                    //do operation
                    switch (conditionToken.Operator)
                    {
                        case LexPath.TokenOperator.Eq:
                            conditionResult = leftValue == rightValue;
                            break;
                        case LexPath.TokenOperator.Ne:
                            conditionResult = leftValue != rightValue;
                            break;
                        case LexPath.TokenOperator.StartWith:
                            conditionResult = leftValue.StartsWith(rightValue);
                            break;
                        case LexPath.TokenOperator.Contains:
                            conditionResult = leftValue.Contains(rightValue);
                            break;
                    }

                    if (conditionToken.Operator == LexPath.TokenOperator.Lt
                        || conditionToken.Operator == LexPath.TokenOperator.Gt
                        )
                    {
                        double leftNum;
                        var isLeftNum = double.TryParse(leftValue, out leftNum);
                        double rightNum;
                        var isRightNum = double.TryParse(rightValue, out rightNum);

                        if(isLeftNum && isRightNum)
                        {
                            switch (conditionToken.Operator)
                            {
                                case LexPath.TokenOperator.Lt:
                                    conditionResult = leftNum < rightNum;
                                    break;
                                case LexPath.TokenOperator.Gt:
                                    conditionResult = leftNum > rightNum;
                                    break;
                            }
                        }
                    }

                    //set total condition result
                    if (conditionToken.Kind == LexPath.TokenKind.ConditionStart)
                        totalConditionResult = conditionResult;
                    if (conditionToken.Kind == LexPath.TokenKind.ConditionAnd)
                        totalConditionResult = totalConditionResult && conditionResult;
                    if (conditionToken.Kind == LexPath.TokenKind.ConditionOr)
                        totalConditionResult = totalConditionResult || conditionResult;

                    conditionToken = conditionToken.Next;

                    if (conditionToken != null && conditionToken.Kind == LexPath.TokenKind.Undefined &&
                        string.IsNullOrEmpty(conditionToken.PathExp) && conditionToken.Next == null)
                        conditionToken = null;
                }

                //add element if true condition
                if (totalConditionResult)
                    result.Elements.Add(element);
            }

            result.Elements = result.Elements.Distinct(new CIFModel.NodeComparer()).ToList();

            result.Elements = result.Elements.OrderBy(x => query._model.GetElemenID(x, query)).ToList();

            return result;
        }

        public override MethodDescription[] GetMethodNames()
        {
            return new MethodDescription[]{new MethodDescription{IsUserMethod = false} };
        }
    }
}
